/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-12
 * V4.0
 */
package com.jphenix.servlet.workflow.script;

import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.servlet.api.IServletConfig;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Hashtable;


/**
 * 脚本类加载器
 * 
 * 2022-09-04 隔离了ServletApi，兼容新老Tomcat
 * 
 * @author 刘虻
 * 2012-11-7 下午3:20:48
 */
@ClassInfo({"2022-09-04 21:58","脚本类加载器"})
public class JaScriptClassLoader extends ClassLoader {

	protected final boolean debug; //是否为调试状态
	protected final File repository; //生成的class类根路径
	protected final IServletConfig config; //Servlet配置信息类
	protected final Hashtable<String,Class<?>> classCache; //类缓存
	
	/**
	 * 构造函数
	 * @author 刘虻
	 */
	public JaScriptClassLoader(
			File repository, IServletConfig config, boolean debug) {
		super();
		this.repository = repository;
		this.config = config;
		this.debug = debug;
		this.classCache = new Hashtable<String,Class<?>>();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2012-11-07下午02:20:15
	 */
	@Override
    protected Class<?> loadClass(
			String className, boolean resolve) throws ClassNotFoundException {
		//从缓存中尝试获取
		Class<?> jaCls = classCache.get(className);
		if(jaCls == null) {
			//获取类数据
			byte[] classData = loadClassData(className);
			if(classData != null) {
				jaCls = defineClass(className, classData, 0, classData.length);
				if(debug) {
					config.getServletContext().log(className + " loaded by JaScript class loader");
				}
			} else {
				//获取类加载器
				ClassLoader cl = JaScriptManager.class.getClassLoader(); 
				if (cl == null) { 
					jaCls = findSystemClass(className); 
					if(debug) {
						config.getServletContext().log("JaScript "+className + " loaded by system class loader");
					}
				} else { 
					jaCls = cl.loadClass(className);
					if(debug) {
						if(jaCls.getClassLoader() == null) {
							config.getServletContext().log("JaScript "+className + " loaded by system class loader (through servlet class loader)");
						} else {
							config.getServletContext().log("JaScript "+className + " loaded by servlet class loader");
						}
					}
				}
				if(jaCls == null) {
					if(debug) {
						config.getServletContext().log("JaScript failed to load " + className);
					}
					return null;
				}
			}
			classCache.put(className, jaCls);
		}
		if(resolve) {
			resolveClass(jaCls);
		}
		return jaCls;
	}

	/**
	 * 获取Ja脚本类数据
	 * @author 刘虻
	 * 2012-11-07下午02:21:44
	 * @param className Ja脚本类名
	 * @return Ja脚本类数据
	 */
	protected byte[] loadClassData(String className) {
		
		DataInputStream	in; //文件读入流
		byte[] classData; //返回值
		if(!className.startsWith("_ja.")) {
			return null;
		}
		//获取目标类文件对象
		File classFile = 
				JaCompiler.getFileForClass(repository, className, ".class");
		try {
			in = new DataInputStream(new FileInputStream(classFile));
			try {
				classData = new byte[(int) classFile.length()];
				in.readFully(classData, 0, classData.length);
				return classData;
			} finally {
				in.close();
			}
		} catch(IOException ioexc) {}
		return null;
	}
}
